<template>
  <div class="content-block">
    <h4>{{ $t('draftSignSet') }}</h4>
    <div class="gesture-container">
      <canvas
          ref="gestureCanvas"
          width="250"
          height="250"
          class="gesture-canvas"
      ></canvas>
      <p class="gesture-hint small-text">{{ $t('gesture-hint small-text') }}</p>
      <button class="reset-btn" @click="resetGesture">{{ $t('reset-btn') }}</button>
    </div>
  </div>
</template>

<script setup>
import { ref, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'
const gestureCanvas = ref(null)
const canvasContext = ref(null)
const pointPositions = ref([])
const pattern = ref([])
const isMouseDown = ref(false)
const linePath = ref([])
let gestureCode = ref('')
const { t } = useI18n()

const initGestureCanvas = () => {
  canvasContext.value = gestureCanvas.value.getContext("2d")
  initPoints()
  drawPoints()

  gestureCanvas.value.addEventListener("mousedown", startDrawing)
  gestureCanvas.value.addEventListener("mousemove", onDrawing)
  gestureCanvas.value.addEventListener("mouseup", endDrawing)
  gestureCanvas.value.addEventListener("mouseleave", endDrawing)
  gestureCanvas.value.addEventListener("touchstart", startDrawing)
  gestureCanvas.value.addEventListener("touchmove", onDrawing)
  gestureCanvas.value.addEventListener("touchend", endDrawing)
}

const initPoints = () => {
  pointPositions.value = []
  const canvasSize = 250
  const offset = 40
  const gap = (canvasSize - 2 * offset) / 2
  for (let row = 0; row < 3; row++) {
    for (let col = 0; col < 3; col++) {
      pointPositions.value.push({
        x: offset + col * gap,
        y: offset + row * gap,
        hit: false
      })
    }
  }
}

const drawPoints = () => {
  clearCanvas()
  const ctx = canvasContext.value

  if (linePath.value.length > 0) {
    const gradient = ctx.createLinearGradient(
        linePath.value[0].x, linePath.value[0].y,
        linePath.value[linePath.value.length - 1].x, linePath.value[linePath.value.length - 1].y
    )
    gradient.addColorStop(0, '#3b82f6')
    gradient.addColorStop(1, '#93c5fd')

    ctx.strokeStyle = gradient
    ctx.lineWidth = 4
    ctx.lineCap = 'round'
    ctx.shadowColor = 'rgba(59, 130, 246, 0.3)'
    ctx.shadowBlur = 6
    ctx.beginPath()
    linePath.value.forEach((point, index) => {
      if (index === 0) ctx.moveTo(point.x, point.y)
      else ctx.lineTo(point.x, point.y)
    })
    ctx.stroke()
  }

  pointPositions.value.forEach(point => {
    ctx.beginPath()
    ctx.arc(point.x, point.y, 14, 0, Math.PI * 2)

    if (point.hit) {
      const gradient = ctx.createRadialGradient(
          point.x, point.y, 0,
          point.x, point.y, 14
      )
      gradient.addColorStop(0, '#3b82f6')
      gradient.addColorStop(1, '#93c5fd')
      ctx.fillStyle = gradient
      ctx.shadowColor = 'rgba(59, 130, 246, 0.5)'
    } else {
      ctx.fillStyle = '#ffffff'
      ctx.shadowColor = 'rgba(0, 0, 0, 0.1)'
    }

    ctx.shadowBlur = 8
    ctx.shadowOffsetX = 0
    ctx.shadowOffsetY = 1
    ctx.strokeStyle = point.hit ? '#1e40af' : '#dbeafe'
    ctx.lineWidth = 1.5

    ctx.fill()
    ctx.stroke()
  })
}

const clearCanvas = () => {
  canvasContext.value.clearRect(0, 0, 250, 250)
}

const getEventPos = (e) => {
  const rect = gestureCanvas.value.getBoundingClientRect()
  const clientX = e.touches ? e.touches[0].clientX : e.clientX
  const clientY = e.touches ? e.touches[0].clientY : e.clientY
  return {
    x: clientX - rect.left,
    y: clientY - rect.top
  }
}

const checkAndAddPoint = (pos) => {
  for (let i = 0; i < pointPositions.value.length; i++) {
    const point = pointPositions.value[i]
    const distance = Math.sqrt(Math.pow(point.x - pos.x, 2) + Math.pow(point.y - pos.y, 2))
    if (distance < 18 && !point.hit) {
      point.hit = true
      pattern.value.push(point)
      linePath.value.push({x: point.x, y: point.y})
      drawPoints()
      break
    }
  }
}

const startDrawing = (e) => {
  e.preventDefault()
  resetGesture()
  isMouseDown.value = true
  const pos = getEventPos(e)
  checkAndAddPoint(pos)
}

const onDrawing = (e) => {
  if (!isMouseDown.value) return
  e.preventDefault()
  const pos = getEventPos(e)
  drawPoints()
  const ctx = canvasContext.value
  if (linePath.value.length > 0) {
    ctx.beginPath()
    ctx.moveTo(linePath.value[linePath.value.length - 1].x, linePath.value[linePath.value.length - 1].y)
    ctx.lineTo(pos.x, pos.y)
    ctx.stroke()
  }
  checkAndAddPoint(pos)
}

const endDrawing = (e) => {
  if (!isMouseDown.value) return
  e.preventDefault()
  isMouseDown.value = false
  drawPoints()
  if (pattern.value.length < 4) {
    ElMessage.error(t('error.minPoints'))
    resetGesture()
  } else {
    const code = pattern.value.map(point =>
        pointPositions.value.indexOf(point) + 1
    ).join('')
    ElMessage.success(t('success.patternRecorded', { code }))
    sessionStorage.setItem('draft', code)
  }
}

const resetGesture = () => {
  pointPositions.value.forEach(point => point.hit = false)
  pattern.value = []
  linePath.value = []
  drawPoints()
}

const getGestureCode = () => {
  if (pattern.value.length < 4) {
    return null
  }
  return gestureCode.value
}

nextTick(() => {
  initGestureCanvas()
})
import {defineExpose} from 'vue'
// 暴露方法
defineExpose({
  getGestureCode,
  resetGesture
})
</script>

<style scoped>
.content-block {
  padding: 1.5vh 0;
}

.content-block h4 {
  margin: 0.5vh 0;
  font-size: 14px;
  font-weight: 500;
}

.gesture-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 1vh;
}

.gesture-hint {
  margin: 1vh 0;
  color: #666;
  text-align: center;
}

.reset-btn {
  padding: 6px 12px;
  background: #f0f2f5;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  color: #606266;
  cursor: pointer;
  font-size: 12px;
  transition: all 0.2s;
}

.reset-btn:hover {
  background: #e4e7ed;
}

.gesture-canvas {
  width: 250px;
  height: 250px;
  background: #f8fafc;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  cursor: pointer;
}
</style>
